{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-02-10T02:34:23.041827Z",
     "start_time": "2025-02-10T02:34:19.636535Z"
    }
   },
   "source": [
    "# 导入库\n",
    "import matplotlib as mpl\n",
    "# Matplotlib 绘制的图形会直接嵌入到 Notebook 的输出单元格中，而不是弹出一个独立的窗口\n",
    "%matplotlib inline\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "\n",
    "# os库提供了一种使用操作系统相关功能的便捷方式，允许与操作系统进行交互\n",
    "import os\n",
    "\n",
    "# sys库主要用于处理Python运行时的环境相关信息以及与解释器的交互\n",
    "import sys\n",
    "import time\n",
    "\n",
    "# tqdm库是一个快速，可扩展的Python进度条，可以在 Python 长循环中添加一个进度提示信息，用户只需要封装任意的迭代器 tqdm(iterator)，即可获得一个进度条显示迭代进度。\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "\n",
    "# torch.nn是PyTorch中用于构建神经网络的模块\n",
    "import torch.nn as nn\n",
    "\n",
    "# torch.nn.functional是PyTorch中包含了神经网络的一些常用函数\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# Python 中的一个属性，用于获取当前 Python 解释器的版本信息。它返回一个命名元组（named tuple）\n",
    "print(sys.version_info)\n",
    "\n",
    "# 遍历模块，打印模块名称和版本信息，快速检查当前环境中安装的某些常用 Python 库的版本信息\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "# 判断是否有 GPU，如果有，则使用 GPU 进行训练，否则使用 CPU 进行训练\n",
    "# torch.cuda.is_available()用于判断是否有GPU\n",
    "# torch.device(\"cuda:0\")创建一个 PyTorch 设备对象，表示使用第一个 GPU（索引为 0）\n",
    "# torch.device(\"cpu\")创建一个 PyTorch 设备对象，表示使用 CPU\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.3.1+cu121\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 数据准备",
   "id": "e6eb06b611a1b676"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "功能: 处理 CIFAR-10 数据集的路径和标签信息，解析 CSV 文件并生成图像路径和标签的列表。\n",
    "\n",
    "原理:\n",
    "\n",
    "使用 Path 对象处理文件路径。\n",
    "\n",
    "解析 CSV 文件，提取图像 ID 和标签。\n",
    "\n",
    "拼接图像文件的完整路径。\n",
    "\n",
    "作用:\n",
    "\n",
    "集中管理数据集的路径。\n",
    "\n",
    "解析 CSV 文件，生成图像路径和标签的列表。\n",
    "\n",
    "为什么这样做:\n",
    "\n",
    "使用 Path 对象可以更方便地处理路径，避免硬编码。\n",
    "\n",
    "解析 CSV 文件可以将标签信息与图像路径关联起来，方便后续加载数据"
   ],
   "id": "695b0ec10711c68b"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T02:55:58.468406Z",
     "start_time": "2025-02-10T02:55:57.409776Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# Path: 用于处理文件路径。\n",
    "from pathlib import Path\n",
    "\n",
    "# 定义数据集的根目录为 ./cifar-10/\n",
    "# 使用 Path 对象处理文件路径\n",
    "DATA_DIR = Path(\"./cifar-10\")\n",
    "\n",
    "train_lables_file = DATA_DIR / \"trainLabels.csv\"  # 训练集标签csv文件\n",
    "test_csv_file = DATA_DIR / \"sampleSubmission.csv\"  #测试集模板csv文件\n",
    "train_folder = DATA_DIR / \"train\"  # 训练集图片文件夹\n",
    "test_folder = DATA_DIR / \"test\"  # 测试集图片文件夹\n",
    "\n",
    "#所有的类别\n",
    "class_names = [\n",
    "    'airplane',\n",
    "    'automobile',\n",
    "    'bird',\n",
    "    'cat',\n",
    "    'deer',\n",
    "    'dog',\n",
    "    'frog',\n",
    "    'horse',\n",
    "    'ship',\n",
    "    'truck',\n",
    "]\n",
    "\n",
    "\n",
    "# 定义一个函数 parse_csv_file，用于解析 CSV 文件并返回图像路径和标签的列表\n",
    "# filepath: CSV 文件的路径。\n",
    "# folder: 图像文件夹的路径\n",
    "# 读取 CSV 文件，解析每一行，生成图像路径和标签的元组列表\n",
    "def parse_csv_file(filepath, folder):\n",
    "    # 初始化一个空列表 results，用于存储解析结果\n",
    "    # 使用列表存储图像路径和标签的元组,方便后续访问和操作解析结果\n",
    "    results = []\n",
    "\n",
    "    # 打开 CSV 文件，读取所有行并跳过第一行（表头）\n",
    "    # 使用 open 函数打开文件，readlines() 读取所有行，[1:] 跳过表头\n",
    "    with open(filepath, 'r') as f:\n",
    "        lines = f.readlines()[1:]\n",
    "\n",
    "    # 遍历每一行数据，去除换行符并按逗号分隔，得到图像 ID 和标签\n",
    "    # 使用 strip('\\n') 去除换行符，split(',') 按逗号分隔,提取图像 ID 和标签\n",
    "    for line in lines:\n",
    "        image_id, label_str = line.strip('\\n').split(',')\n",
    "\n",
    "        # 拼接图像文件的完整路径\n",
    "        # 使用 Path 对象拼接路径，f\"{image_id}.png\" 生成图像文件名\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "\n",
    "        # 将图像路径和标签的元组添加到 results 列表中\n",
    "        results.append((image_full_path, label_str))\n",
    "    return results\n",
    "\n",
    "\n",
    "#  调用 parse_csv_file 函数，解析训练集和测试集的 CSV 文件\n",
    "train_labels_info = parse_csv_file(train_lables_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "\n"
   ],
   "id": "ee74d770da1bdc38",
   "outputs": [],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T02:56:22.157735Z",
     "start_time": "2025-02-10T02:56:22.154340Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import pprint\n",
    "\n",
    "pprint.pprint(train_labels_info[0])\n",
    "pprint.pprint(test_csv_info[0])\n",
    "print(len(train_labels_info), len(test_csv_info))"
   ],
   "id": "db42d62d38e3c844",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(WindowsPath('cifar-10/train/1.png'), 'frog')\n",
      "(WindowsPath('cifar-10/test/1.png'), 'cat')\n",
      "50000 300000\n"
     ]
    }
   ],
   "execution_count": 5
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T02:57:08.893922Z",
     "start_time": "2025-02-10T02:57:08.859799Z"
    }
   },
   "cell_type": "code",
   "source": [
    " train_df = pd.DataFrame(train_labels_info[0:45000])  # 取前45000张图片作为训练集\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:])  # 取后5000张图片作为验证集\n",
    "test_df = pd.DataFrame(test_csv_info)  # 取测试集\n",
    "\n",
    "train_df.columns = ['filepath', 'class']  # 给数据框添加列名\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']"
   ],
   "id": "1c987ef3a1f278c",
   "outputs": [],
   "execution_count": 6
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T02:57:52.373636Z",
     "start_time": "2025-02-10T02:57:52.368784Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(train_df.head())\n",
    "print(valid_df.head())\n",
    "print(test_df.head())"
   ],
   "id": "8d7115ddf766e418",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "               filepath       class\n",
      "0  cifar-10\\train\\1.png        frog\n",
      "1  cifar-10\\train\\2.png       truck\n",
      "2  cifar-10\\train\\3.png       truck\n",
      "3  cifar-10\\train\\4.png        deer\n",
      "4  cifar-10\\train\\5.png  automobile\n",
      "                   filepath       class\n",
      "0  cifar-10\\train\\45001.png       horse\n",
      "1  cifar-10\\train\\45002.png  automobile\n",
      "2  cifar-10\\train\\45003.png        deer\n",
      "3  cifar-10\\train\\45004.png  automobile\n",
      "4  cifar-10\\train\\45005.png    airplane\n",
      "              filepath class\n",
      "0  cifar-10\\test\\1.png   cat\n",
      "1  cifar-10\\test\\2.png   cat\n",
      "2  cifar-10\\test\\3.png   cat\n",
      "3  cifar-10\\test\\4.png   cat\n",
      "4  cifar-10\\test\\5.png   cat\n"
     ]
    }
   ],
   "execution_count": 10
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "模块总结\n",
    "1. 代码结构\n",
    "导入库：加载必要的工具库（如 PIL、torch.utils.data、torchvision.transforms）。\n",
    "定义数据集类：继承 Dataset，实现 __getitem__ 和 __len__ 方法，定义数据加载逻辑。\n",
    "定义预处理方法：使用 transforms.Compose 定义训练和验证数据的预处理和数据增强方法。\n",
    "创建数据集对象：根据模式（train/eval）创建数据集对象，并应用对应的预处理方法。\n",
    "2. 核心功能\n",
    "数据加载：从数据框中加载图像路径和标签，按需加载图像数据。\n",
    "数据预处理：对图像进行大小调整、数据增强（训练时）、归一化等操作。\n",
    "标签转换：将类别名称转换为数值索引，方便模型处理。\n",
    "数据集封装：将数据加载和预处理逻辑封装到 Dataset 类中，便于与 DataLoader 结合使用。\n",
    "3. 关键点\n",
    "Dataset 类：必须实现 __getitem__ 和 __len__ 方法，定义如何获取单个样本和数据集大小。\n",
    "**transforms**：用于图像预处理和数据增强，训练和验证/测试数据的预处理方法可能不同。\n",
    "数据增强：仅用于训练数据，目的是提高模型的泛化能力。\n",
    "归一化：使用数据集的均值和标准差对图像进行归一化，加速模型收敛。\n",
    "4. 快速回忆\n",
    "自定义数据集：继承 Dataset，实现 __getitem__ 和 __len__。\n",
    "数据预处理：使用 transforms.Compose 定义预处理流程。\n",
    "训练数据增强：包括随机旋转、翻转等。\n",
    "验证/测试数据：只需基本预处理（调整大小、归一化）。\n",
    "标签转换：将类别名称映射到数值索引。"
   ],
   "id": "309da82e21e94b78"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:41:09.410287Z",
     "start_time": "2025-02-10T04:41:09.404288Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# PIL（Python Imaging Library）用于图像处理，Image 模块可以加载和操作图像\n",
    "from PIL import Image\n",
    "\n",
    "# Dataset 是 PyTorch 中用于定义数据集的基类\n",
    "# DataLoader 用于批量加载数据，支持多线程和数据打乱\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "# transforms 提供了图像预处理和数据增强的工具，如调整大小、旋转、归一化等\n",
    "from torchvision import transforms\n",
    "\n",
    "\n",
    "# 定义一个自定义数据集类，继承自 PyTorch 的 Dataset 类\n",
    "# CIFAR-10 数据集的加载方式与默认数据集不同，需要自定义\n",
    "class Cifar10Dataset(Dataset):\n",
    "    # 定义一个字典，将数据集模式（train/eval/test）映射到对应的数据框\n",
    "    # 通过 mode 参数快速获取对应的数据集\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "\n",
    "    # 创建一个字典，将类别名称映射到索引（如 \"cat\" -> 0）\n",
    "    # 使用字典推导式生成映射关系\n",
    "    # 模型需要数值标签，而数据通常以类别名称存储，因此需要转换\n",
    "    label_to_idx = {label: idx for idx, label in enumerate(class_names)}\n",
    "\n",
    "    # 创建一个字典，将索引映射回类别名称（如 0 -> \"cat\"）\n",
    "    # 与 label_to_idx 类似，但方向相反\n",
    "    # 在模型预测后，可能需要将索引转换回类别名称以便解释结果\n",
    "    idx_to_label = {idx: label for idx, label in enumerate(class_names)}\n",
    "\n",
    "    # 初始化 Cifar10Dataset 类的实例\n",
    "    # mode：指定数据集模式（train/eval/test）。\n",
    "    # transform：指定图像预处理和数据增强的方法\n",
    "    def __init__(self, mode, transform=None):\n",
    "        # 根据 mode 获取对应的数据框\n",
    "        # 使用字典的 get 方法获取值，如果 mode 不存在则返回 None\n",
    "        self.df = self.df_map.get(mode, None)\n",
    "\n",
    "        # 检查 mode 是否有效，如果无效则抛出错误\n",
    "        # 防止因无效模式导致后续代码出错\n",
    "        if self.df is None:\n",
    "            raise ValueError(\"mode should be one of train, val, test, but got {}\".format(mode))\n",
    "\n",
    "        # 保存 transform 参数到对象属性中\n",
    "        # 在 __getitem__ 方法中会用到 transform\n",
    "        self.transform = transform\n",
    "\n",
    "    # 根据索引获取单个样本（图像和标签）\n",
    "    # Dataset 类的核心方法，定义了如何获取数据,DataLoader 会调用此方法批量加载数据\n",
    "    def __getitem__(self, index):\n",
    "        # 从数据框中获取图像路径和标签\n",
    "        # 使用 iloc 方法按索引获取数据,数据框存储了图像路径和标签，需要按索引提取\n",
    "        img_path, label = self.df.iloc[index]\n",
    "\n",
    "        # 加载图像并转换为 RGB 格式\n",
    "        # Image.open 加载图像，convert('RGB') 确保图像为三通道\n",
    "        img = Image.open(img_path).convert('RGB')\n",
    "\n",
    "        # 对图像应用预处理和数据增强\n",
    "        img = self.transform(img)\n",
    "\n",
    "        # 将类别名称转换为索引,使用 label_to_idx 字典进行转换\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label\n",
    "\n",
    "    def __len__(self):\n",
    "        # 返回数据框的行数，即样本数量\n",
    "        # shape[0] 获取数据框的行数\n",
    "        return self.df.shape[0]\n",
    "\n",
    "\n",
    "# 定义图像的输入大小\n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4368, 0.4268, 0.3947], [0.2464, 0.2418, 0.2358]\n",
    "\n",
    "# 定义训练数据的预处理和数据增强方法\n",
    "# 数据增强（如旋转、翻转）可以提高模型的泛化能力，避免过拟合\n",
    "# 训练时需要增加数据的多样性，同时确保输入数据符合模型的期望格式\n",
    "transforms_train = transforms.Compose([\n",
    "    transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),  # 将图像调整为指定大小（32x32）\n",
    "    transforms.RandomRotation(40),  # 随机旋转图像，最大角度为40度\n",
    "    transforms.RandomHorizontalFlip(),  # 随机水平翻转图像\n",
    "    transforms.ToTensor(),  # 将图像转换为PyTorch张量（Tensor），并将像素值从 [0, 255] 归一化到 [0, 1]。\n",
    "    transforms.Normalize(mean, std)  # 根据均值和标准差对图像进行归一化\n",
    "])\n",
    "\n",
    "# 验证/测试数据不需要数据增强，只需进行基本的预处理\n",
    "# 验证/测试时，需要保持数据的原始分布，以评估模型的真实性能\n",
    "transforms_eval = transforms.Compose([\n",
    "    transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),  # 将图像调整为指定大小（32x32）\n",
    "    transforms.ToTensor(),  # 将图像转换为PyTorch张量（Tensor），并将像素值从 [0, 255] 归一化到 [0, 1]。\n",
    "    transforms.Normalize(mean, std)  # 根据均值和标准差对图像进行归一化\n",
    "])\n",
    "\n",
    "# 创建训练数据集对象\n",
    "train_ds = Cifar10Dataset(\"train\", transforms_train)\n",
    "eval_ds = Cifar10Dataset(\"eval\", transforms_eval)"
   ],
   "id": "5f23dcf49bfb7021",
   "outputs": [],
   "execution_count": 22
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:41:10.041604Z",
     "start_time": "2025-02-10T04:41:10.037728Z"
    }
   },
   "cell_type": "code",
   "source": "train_ds[0][0].shape  # 图片的shape,输入",
   "id": "2f2115ae06317da5",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([3, 32, 32])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 23
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:41:10.354471Z",
     "start_time": "2025-02-10T04:41:10.350975Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(train_ds.idx_to_label)  # 类别映射为idx\n",
    "train_ds.label_to_idx  # idx映射为类别"
   ],
   "id": "b0a59243409748c1",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0: 'airplane', 1: 'automobile', 2: 'bird', 3: 'cat', 4: 'deer', 5: 'dog', 6: 'frog', 7: 'horse', 8: 'ship', 9: 'truck'}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'airplane': 0,\n",
       " 'automobile': 1,\n",
       " 'bird': 2,\n",
       " 'cat': 3,\n",
       " 'deer': 4,\n",
       " 'dog': 5,\n",
       " 'frog': 6,\n",
       " 'horse': 7,\n",
       " 'ship': 8,\n",
       " 'truck': 9}"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:41:11.085386Z",
     "start_time": "2025-02-10T04:41:11.082920Z"
    }
   },
   "cell_type": "code",
   "source": [
    "batch_size = 64\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)\n",
    "eval_dl = DataLoader(eval_ds, batch_size=batch_size, shuffle=False)"
   ],
   "id": "a73b6ecda19c4974",
   "outputs": [],
   "execution_count": 25
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:41:31.242719Z",
     "start_time": "2025-02-10T04:41:11.409824Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "def cal_mean_std(ds):\n",
    "    mean = 0.\n",
    "    std = 0.\n",
    "    for img, _ in ds:\n",
    "        mean += img.mean(dim=(1, 2))\n",
    "        std += img.std(dim=(1, 2))\n",
    "    mean /= len(ds)\n",
    "    std /= len(ds)\n",
    "    return mean, std\n",
    "\n",
    "\n",
    "# 经过 normalize 后 均值为0，方差为1\n",
    "print(cal_mean_std(train_ds))"
   ],
   "id": "283575546b500ffa",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(tensor([ 4.6828e-04, -2.2041e-05, -7.2417e-05]), tensor([1.0000, 1.0002, 1.0004]))\n"
     ]
    }
   ],
   "execution_count": 26
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 模型构建",
   "id": "f67a70245fb9ab83"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:47:22.496898Z",
     "start_time": "2025-02-10T04:47:22.458683Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class CNN(nn.Module):\n",
    "    def __init__(self, num_classes):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Conv2d(in_channels=3, out_channels=128, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(128),  # 批标准化，在通道数做的归一化\n",
    "            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=\"same\"),  #输出尺寸（128，32，32）\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(128),\n",
    "            nn.MaxPool2d(kernel_size=2),  #输出尺寸（128，16，16）\n",
    "            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(256),\n",
    "            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=\"same\"),  #输出尺寸（256，16，16）\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(256),\n",
    "            nn.MaxPool2d(kernel_size=2),  #输出尺寸（256，8，8）\n",
    "            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(512),\n",
    "            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=\"same\"),  #输出尺寸（512，8，8）\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(512),\n",
    "            nn.MaxPool2d(kernel_size=2),  #输出尺寸（512，4，4）\n",
    "            nn.Flatten(),  #展平\n",
    "            nn.Linear(8192, 512),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(512, num_classes),\n",
    "        )  #Sequential自动连接各层，把各层的输出作为下一层的输入\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "\n",
    "\n",
    "for key, value in CNN(len(class_names)).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n"
   ],
   "id": "d8ddb56584b0bee3",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             model.0.weight             paramerters num: 3456\n",
      "              model.0.bias              paramerters num: 128\n",
      "             model.2.weight             paramerters num: 128\n",
      "              model.2.bias              paramerters num: 128\n",
      "             model.3.weight             paramerters num: 147456\n",
      "              model.3.bias              paramerters num: 128\n",
      "             model.5.weight             paramerters num: 128\n",
      "              model.5.bias              paramerters num: 128\n",
      "             model.7.weight             paramerters num: 294912\n",
      "              model.7.bias              paramerters num: 256\n",
      "             model.9.weight             paramerters num: 256\n",
      "              model.9.bias              paramerters num: 256\n",
      "            model.10.weight             paramerters num: 589824\n",
      "             model.10.bias              paramerters num: 256\n",
      "            model.12.weight             paramerters num: 256\n",
      "             model.12.bias              paramerters num: 256\n",
      "            model.14.weight             paramerters num: 1179648\n",
      "             model.14.bias              paramerters num: 512\n",
      "            model.16.weight             paramerters num: 512\n",
      "             model.16.bias              paramerters num: 512\n",
      "            model.17.weight             paramerters num: 2359296\n",
      "             model.17.bias              paramerters num: 512\n",
      "            model.19.weight             paramerters num: 512\n",
      "             model.19.bias              paramerters num: 512\n",
      "            model.22.weight             paramerters num: 4194304\n",
      "             model.22.bias              paramerters num: 512\n",
      "            model.24.weight             paramerters num: 5120\n",
      "             model.24.bias              paramerters num: 10\n"
     ]
    }
   ],
   "execution_count": 27
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:47:34.780488Z",
     "start_time": "2025-02-10T04:47:34.754705Z"
    }
   },
   "cell_type": "code",
   "source": [
    "total_params = sum(p.numel() for p in CNN(len(class_names)).parameters() if p.requires_grad)\n",
    "print(f\"Total trainable parameters: {total_params}\")"
   ],
   "id": "e434e59eb6e8d3",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total trainable parameters: 8779914\n"
     ]
    }
   ],
   "execution_count": 28
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 模型训练",
   "id": "64a1b6c709fb81f6"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:51:01.119841Z",
     "start_time": "2025-02-10T04:51:01.070889Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)  # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "\n",
    "        preds = logits.argmax(axis=-1)  # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "\n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "id": "536a522050046630",
   "outputs": [],
   "execution_count": 29
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:51:09.987420Z",
     "start_time": "2025-02-10T04:51:07.290242Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "\n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\",\n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "\n",
    "        )\n",
    "\n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "id": "2ae85bf8b07e0b17",
   "outputs": [],
   "execution_count": 30
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:51:12.939765Z",
     "start_time": "2025-02-10T04:51:12.935269Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "\n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "id": "b2720be60fa52461",
   "outputs": [],
   "execution_count": 31
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:51:18.263856Z",
     "start_time": "2025-02-10T04:51:18.259857Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else:\n",
    "            self.counter += 1\n",
    "\n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "id": "2373b91461b2a7a3",
   "outputs": [],
   "execution_count": 32
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T04:52:06.733887Z",
     "start_time": "2025-02-10T04:52:06.560354Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 训练\n",
    "def training(\n",
    "        model,\n",
    "        train_loader,\n",
    "        val_loader,\n",
    "        epoch,\n",
    "        loss_fct,\n",
    "        optimizer,\n",
    "        tensorboard_callback=None,\n",
    "        save_ckpt_callback=None,\n",
    "        early_stop_callback=None,\n",
    "        eval_step=500,\n",
    "):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)  #最大值的索引\n",
    "\n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())  # 计算准确率\n",
    "                loss = loss.cpu().item()  # 计算损失\n",
    "                # record\n",
    "\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step  # 记录每一步的损失和准确率\n",
    "                })\n",
    "\n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "\n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step,\n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                        )\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "\n",
    "    return record_dict\n",
    "\n",
    "\n",
    "epoch = 20\n",
    "\n",
    "model = CNN(num_classes=10)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/cifar-10\")\n",
    "tensorboard_callback.draw_model(model, [1, 3, IMAGE_SIZE, IMAGE_SIZE])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/cifar-10\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)"
   ],
   "id": "50fc1f19b1aa9664",
   "outputs": [],
   "execution_count": 34
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T05:11:39.156186Z",
     "start_time": "2025-02-10T04:52:21.939277Z"
    }
   },
   "cell_type": "code",
   "source": [
    "model = model.to(device)\n",
    "\n",
    "record = training(\n",
    "    model,\n",
    "    train_dl,\n",
    "    eval_dl,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    ")"
   ],
   "id": "d16b07a2fb534094",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/14080 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "2667022778254ad0b43c4d50a7bd3495"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 35
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T05:11:39.330413Z",
     "start_time": "2025-02-10T05:11:39.160578Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):\n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ],
   "id": "f91899119de0ddef",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 36
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 评估",
   "id": "d185529530cf400b"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-10T05:11:42.050563Z",
     "start_time": "2025-02-10T05:11:39.331533Z"
    }
   },
   "cell_type": "code",
   "source": [
    "model.load_state_dict(torch.load(\"checkpoints/cifar-10/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "id": "4c9b9c5257f98703",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.4292\n",
      "accuracy: 0.8706\n"
     ]
    }
   ],
   "execution_count": 37
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 推理",
   "id": "7f31ff8397f8e2a7"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-11T02:00:51.145508Z",
     "start_time": "2025-02-11T01:51:40.825975Z"
    }
   },
   "cell_type": "code",
   "source": [
    "test_ds = Cifar10Dataset(\"test\", transform=transforms_eval)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, drop_last=False)\n",
    "\n",
    "preds_collect = []  # 预测结果收集器\n",
    "model.eval()\n",
    "for data, fake_label in tqdm(test_dl):\n",
    "    data = data.to(device=device)\n",
    "    logits = model(data)  #得到预测结果\n",
    "    preds = [test_ds.idx_to_label[idx] for idx in\n",
    "             logits.argmax(axis=-1).cpu().tolist()]  # 得到预测类别，idx_to_label是id到字符串类别的映射\n",
    "    preds_collect.extend(preds)\n",
    "\n",
    "test_df[\"label\"] = preds_collect  # 增加预测类别列,比赛要求这一列是label\n",
    "test_df.head()"
   ],
   "id": "154d486e3d22a8ee",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/4688 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "645187f7500f4151bb642eecfa5ff73b"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "              filepath class       label\n",
       "0  cifar-10\\test\\1.png   cat        bird\n",
       "1  cifar-10\\test\\2.png   cat    airplane\n",
       "2  cifar-10\\test\\3.png   cat  automobile\n",
       "3  cifar-10\\test\\4.png   cat        ship\n",
       "4  cifar-10\\test\\5.png   cat    airplane"
      ],
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>filepath</th>\n",
       "      <th>class</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>cifar-10\\test\\1.png</td>\n",
       "      <td>cat</td>\n",
       "      <td>bird</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>cifar-10\\test\\2.png</td>\n",
       "      <td>cat</td>\n",
       "      <td>airplane</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>cifar-10\\test\\3.png</td>\n",
       "      <td>cat</td>\n",
       "      <td>automobile</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>cifar-10\\test\\4.png</td>\n",
       "      <td>cat</td>\n",
       "      <td>ship</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>cifar-10\\test\\5.png</td>\n",
       "      <td>cat</td>\n",
       "      <td>airplane</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 38
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-11T02:01:51.428271Z",
     "start_time": "2025-02-11T02:01:51.325645Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 导出 submission.csv\n",
    "test_df.to_csv(\"submission.csv\", index=False)"
   ],
   "id": "6de86661e2a31fbd",
   "outputs": [],
   "execution_count": 39
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "f29fa9b4d6ea4425"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
